<html>
<head>
<link rel="shortcut icon" href="./favicon.ico">
<link rel="stylesheet" type="text/css" href="./style.css">
<link rel="canonical" href="./Pulse_to_Pipeline.html">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Wraps a module with an output pulse interface inside a ready/valid output handshake interface.  *The connected module must have at least one pipeline stage from input to output. No combinational paths allowed else the input and output handshake logic will form a loop.*">
<title>Pulse to Pipeline</title>
</head>
<body>

<p class="inline bordered"><b><a href="./Pulse_to_Pipeline.v">Source</a></b></p>
<p class="inline bordered"><b><a href="./legal.html">License</a></b></p>
<p class="inline bordered"><b><a href="./index.html">Index</a></b></p>

<h1>Pulse to Pipeline Interface</h1>
<p>Wraps a module with an output pulse interface inside a ready/valid output
 handshake interface.  <em>The connected module must have at least one pipeline
 stage from input to output. No combinational paths allowed else the input
 and output handshake logic will form a loop.</em></p>
<p>When we have a module that cannot be fully pipelined due to a data
 dependency (e.g.: because of a backwards loop in the pipeline, or simply by
 the iterative nature of the implemented algorithm), and thus cannot accept
 a new input every cycle (i.e.: it has an initiation interval greater than
 1), then we design the connected module to accept a new input with
 a one-cycle valid pulse, and to signal the updated output 1 or more cycles
 later with a corresponding one-cycle output pulse. </p>
<p>This Pulse to Pipeline module converts that output pulse interface into
 a pipeline output with a ready/valid handshake, and once read out, signals
 the corresponding input interface that new data can be accepted.</p>
<p>Note that the connected module result can only be read out once, even if
 held steady until the next update. This is necessary to meet some Kahn
 Process Network criteria, and to allow for the connected module to use its
 output registers as part of its computations, rather than have extra
 buffers (which we instead hold here as the <code>output_buffer</code>).</p>
<p>We assume here that the connected module is not C-Slowed, though that is
 allowed. You will have to keep track of the separate computation streams
 yourself in the enclosing module.</p>
<h2>Choosing the Output Buffer Type</h2>
<p>An output buffer is necessary to cut the backwards combinational path from
 <code>ready_out</code> to <code>module_ready</code>, as well as to get the best performance and
 expected behaviour, depending on the connected module. Set
 <code>OUTPUT_BUFFER_TYPE</code> (and maybe <code>FIFO_BUFFER_DEPTH</code>, <code>FIFO_BUFFER_RAMSTYLE</code>,
 and <code>OUTPUT_BUFFER_CIRCULAR</code>) as required.</p>
<ul>
<li>A <strong>Skid Buffer</strong> is generally the right choice: it allows the connected module
 to start a new computation while the <code>output_buffer</code> waits for the next
 pipeline stage to read out the previous result.</li>
<li>Use a <strong>Half-Buffer</strong> when the connected module should NOT be allowed to start
 a new computation until the previous result has been read out of the
 <code>output_buffer</code>. </li>
<li>Use a <strong>FIFO Buffer</strong> when the later pipeline stages read in a bursty
 pattern, so the connected module can get through multiple computations in
 the meantime.</li>
<li>Set <code>OUTPUT_BUFFER_CIRCULAR</code> to a non-zero value for cases where you
 always want the latest data available to the output, regardless of
 intermediate changes which will be lost.</li>
</ul>

<pre>
`default_nettype none

module <a href="./Pulse_to_Pipeline.html">Pulse_to_Pipeline</a>
#(
    parameter WORD_WIDTH                = 0,
    parameter OUTPUT_BUFFER_TYPE        = "", // "HALF", "SKID", "FIFO"
    parameter OUTPUT_BUFFER_CIRCULAR    = 0,  // non-zero to enable
    parameter FIFO_BUFFER_DEPTH         = 0,  // Only for "FIFO"
    parameter FIFO_BUFFER_RAMSTYLE      = ""  // Only for "FIFO"
)
(
    input   wire                        clock,
    input   wire                        clear,

    // Pipeline output
    output  wire                        valid_out,
    input   wire                        ready_out,
    output  wire    [WORD_WIDTH-1:0]    data_out,

    // Pulse interface from connected module
    input   wire    [WORD_WIDTH-1:0]    module_data_out,
    input   wire                        module_data_out_valid,

    // Signal that the module can accept the next input
    output  reg                         module_ready
);

    initial begin
        module_ready = 1'b0;
    end
</pre>

<p>Express the usual conditions to complete a ready/valid handshake.  The
 "internal" signals connect to a Skid Buffer that deals with the final
 output handshake to the downstream pipeline. When we have transferred the
 module's output data to the Skid Buffer, we signal the module is ready for
 the next input.</p>

<pre>
    reg  valid_out_internal     = 1'b0;
    wire ready_out_internal;
    reg  output_handshake_done  = 1'b0;

    always @(*) begin
        output_handshake_done   = (valid_out_internal == 1'b1) && (ready_out_internal == 1'b1);
        module_ready            = (output_handshake_done == 1'b1);
    end
</pre>

<p>The output ready/valid handshake starts when the connected module updates
 its output data.</p>

<pre>
    wire valid_out_latched;

    <a href="./Pulse_Latch.html">Pulse_Latch</a>
    #(
        .RESET_VALUE    (1'b0)
    )
    generate_valid_out_latched
    (
        .clock          (clock),
        .clear          (output_handshake_done),
        .pulse_in       (module_data_out_valid),
        .level_out      (valid_out_latched)
    );
</pre>

<p>Pass the module pulse directly, and also latch it. This removes a cycle of
 latency and still allows the output handshake to complete later if the
 downstream logic is not ready.</p>

<pre>
    always @(*) begin
        valid_out_internal = (valid_out_latched == 1'b1) || (module_data_out_valid == 1'b1);
    end
</pre>

<p>Buffer the output handshake to cut the backwards combinational path from
 <code>ready_out</code> to <code>module_ready</code>.  A Half-Buffer blocks <code>module_ready</code> until
 it is read out, and the data is the first buffered one since last read out.
 A Skid Buffer allows overlap by raising <code>module_ready</code> while holding
 1 previous result, but holding 2 results will cause it to block.  A FIFO
 buffer will allow overlap and hold up to <code>FIFO_BUFFER_DEPTH</code> values before
 blocking.</p>

<pre>
    generate

        if (OUTPUT_BUFFER_TYPE == "HALF") begin : gen_half
            <a href="./Pipeline_Half_Buffer.html">Pipeline_Half_Buffer</a>
            #(
                .WORD_WIDTH         (WORD_WIDTH),
                .CIRCULAR_BUFFER    (OUTPUT_BUFFER_CIRCULAR)
            )
            output_buffer
            (
                .clock          (clock),
                .clear          (clear),

                .input_valid    (valid_out_internal),
                .input_ready    (ready_out_internal),
                .input_data     (module_data_out),

                .output_valid   (valid_out),
                .output_ready   (ready_out),
                .output_data    (data_out)
            );
        end
        else if (OUTPUT_BUFFER_TYPE == "SKID") begin : gen_skid
            <a href="./Pipeline_Skid_Buffer.html">Pipeline_Skid_Buffer</a>
            #(
                .WORD_WIDTH         (WORD_WIDTH),
                .CIRCULAR_BUFFER    (OUTPUT_BUFFER_CIRCULAR)
            )
            output_buffer
            (
                .clock          (clock),
                .clear          (clear),

                .input_valid    (valid_out_internal),
                .input_ready    (ready_out_internal),
                .input_data     (module_data_out),

                .output_valid   (valid_out),
                .output_ready   (ready_out),
                .output_data    (data_out)
            );
        end
        else if (OUTPUT_BUFFER_TYPE == "FIFO") begin : gen_fifo
            <a href="./Pipeline_FIFO_Buffer.html">Pipeline_FIFO_Buffer</a>
            #(
                .WORD_WIDTH         (WORD_WIDTH),
                .DEPTH              (FIFO_BUFFER_DEPTH),
                .RAMSTYLE           (FIFO_BUFFER_RAMSTYLE),
                .CIRCULAR_BUFFER    (OUTPUT_BUFFER_CIRCULAR)
            )
            output_buffer
            (
                .clock          (clock),
                .clear          (clear),

                .input_valid    (valid_out_internal),
                .input_ready    (ready_out_internal),
                .input_data     (module_data_out),

                .output_valid   (valid_out),
                .output_ready   (ready_out),
                .output_data    (data_out)
            );
        end

    endgenerate

endmodule
</pre>

<hr>
<p><a href="./index.html">Back to FPGA Design Elements</a>
<center><a href="https://fpgacpu.ca/">fpgacpu.ca</a></center>
</body>
</html>

